package com.ruoyi.web.controller.BT;

import cn.dev33.satoken.annotation.SaIgnore;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.web.Server.BT.TorrentCommentService;
import com.ruoyi.web.Server.BT.TorrentService;
import com.ruoyi.web.Server.BT.TrackerURLService;
import com.ruoyi.web.Server.BT.PasskeyManager;
import com.ruoyi.web.Server.sys.ResPassKeyService;
import com.ruoyi.web.controller.common.CommonResultStatus;
import com.ruoyi.web.controller.common.Constants;
import com.ruoyi.web.controller.common.base.I18nMessage;
import com.ruoyi.web.controller.common.base.PageUtil;
import com.ruoyi.web.controller.common.base.Result;
import com.ruoyi.web.controller.common.exception.RocketPTException;
import com.ruoyi.web.dao.BT.SuggestDao;
import com.ruoyi.web.domain.BT.*;
import com.ruoyi.web.Server.sys.UserService;

import com.ruoyi.web.domain.BT.dto.TorrentSearchRequest;
import com.ruoyi.web.domain.BT.dto.TorrentSearchResult;
import com.ruoyi.web.domain.sys.UserEntity;
import com.ruoyi.web.domain.sys.UserPassKey;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author Jrx
 */
@RestController
@Tag(name = "torrent种子相关", description = Constants.FinishStatus.FINISHED)
@RequiredArgsConstructor
@RequestMapping("/torrent")
@Validated
public class TorrentController {

    private final TorrentService torrentService;
    private final TrackerURLService trackerURLService;
    private final SuggestDao suggestDao;
    private final UserService userService;
    private final TorrentCommentService torrentCommentService;
    private final ResPassKeyService passKeyService;
    /**
     * The purpose of the method:
     *
     * 种子搜索
     * {@code @date} 2025/6/8 13:11
     */
    @PostMapping("/search")
    public Result searchTorrents(@RequestBody TorrentSearchRequest request) {
        Page<TorrentSearchResult> result = torrentService.searchTorrents(request);
        return Result.ok(result);
    }

    /**
     * 种子列表查询
     */
    
    @Operation(summary = "种子列表查询", description = "种子列表条件查询-分页-排序")
    @ApiResponse(responseCode = "0", description = "操作成功",
            content = {@Content(mediaType = "application/json",
                    schema = @Schema(implementation = TorrentVO.class))
            })
    @PostMapping("/list")
    public Result list(@RequestBody TorrentParam param) {
        param.validOrder(param.getOrderKey(TorrentEntity.class));
        param.buildLike();
        PageUtil.startPage(param);

        List<TorrentEntity> list = torrentService.getBaseMapper().search(param);

        return Result.ok(list, PageUtil.getPage(list));
    }

    @PostMapping("/myList")
    public Result MyList() {
        Integer userId = userService.getUserId();
        Map<String, Object>  param = new HashMap<>();
        param.put("owner", userId);
        // 使用MyBatis-Plus的条件构造器创建查询
        QueryWrapper<TorrentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("owner", userId);

        // 获取分页参数（如果有）
        Map<String, Object> pageParam = new HashMap<>();
        int pageNum = (int) pageParam.getOrDefault("pageNum", 1);
        int pageSize = (int) pageParam.getOrDefault("pageSize", 10);

        // 创建分页对象
        Page<TorrentEntity> page = new Page<>(pageNum, pageSize);

        // 执行分页查询
        IPage<TorrentEntity> torrentPage = torrentService.page(page, queryWrapper);

        Map<String, Object> data = new HashMap<>();
        data.put("rows", torrentPage.getRecords());
        data.put("total", torrentPage.getTotal());
        data.put("pages", torrentPage.getPages());
        data.put("current", torrentPage.getCurrent());
        data.put("size", torrentPage.getSize());

        return Result.ok(data);
    }

    @Operation(summary = "种子搜索建议")
    @GetMapping("/suggest")
    @Parameter(name = "q", description = "关键字", required = true, in = ParameterIn.QUERY)
    @ApiResponse(responseCode = "0", description = "操作成功", content = {
            @Content(mediaType = "application/json", schema = @Schema(implementation =
                    SuggestVo.class))
    })
    public Result getSuggestions(@RequestParam(required = false) String q) {

        if (StringUtils.isEmpty(q)) {
            return Result.ok(new ArrayList<>());
        }

        List<SuggestVo> suggests = suggestDao.getSuggestions(q.trim() + "%");
        List<SuggestVo> result = new ArrayList<>();
        int i = 0;
        for (SuggestVo suggest : suggests) {
            if (suggest.getSuggest().length() > 25) {
                continue;
            }
            result.add(suggest);

            i++;
            if (i >= 5) {
                break;
            }
        }

        return Result.ok(result);
    }

    
    @Operation(summary = "种子详情查询")
    @ApiResponse(responseCode = "0", description = "操作成功", content = {
            @Content(mediaType = "application/json", schema = @Schema(implementation =
                    TorrentEntity.class))
    })
    @PostMapping("/info/{id}")
    public Result info(@PathVariable("id") Integer id) {
        TorrentEntity entity = torrentService.getById(id);
        return Result.ok(entity);
    }

    
    @Operation(summary = "新增种子")
    @PostMapping("/add")
    public Result add(@RequestBody TorrentAddParam param) {
        Integer id = torrentService.add(param);
        return Result.ok(id);
    }


    
    @Operation(summary = "审核种子")
    @PostMapping("/audit")
    public Result audit(@RequestBody @Validated TorrentAuditParam param) {
        torrentService.audit(param);
        return Result.ok();
    }

    /**
     * 收藏或者取消收藏
     */
    @Operation(summary = "收藏或者取消收藏种子")
    @Parameter(name = "id", description = "种子ID", required = true, in = ParameterIn.QUERY)
    @PostMapping("/favorite")
    public Result favorite(Integer id) {
        torrentService.favorite(id, userService.getUserId());
        return Result.ok();
    }




    /**
     * 生成邀请码
     */
    @GetMapping("/generatePassKey")
    public Result generatePassKey() {
        try {
            int userId = userService.getUserId();

            // 生成新的邀请码
            UserPassKey passKey = passKeyService.generatePassKey(userId);
            // 成功响应
            return Result.ok(passKey);
        } catch (Exception e) {
            return Result.error("生成邀请码失败: " + e.getMessage());
        }
    }


    @Operation(summary = "上传文件并生成种子")
    @PostMapping("/upload")
    public Result upload(@RequestPart("file") MultipartFile file,
                                         @RequestParam Integer id) {
        try {
            if (file.isEmpty()) {
                throw new RocketPTException(CommonResultStatus.PARAM_ERROR,
                        I18nMessage.getMessage("torrent_empty"));
            }

            String originalFilename = org.springframework.util.StringUtils.cleanPath(file.getOriginalFilename());
            boolean isTorrentFile = originalFilename.endsWith(".torrent");
            String filename = originalFilename; // 原始文件名（可能包含中文）
            byte[] fileBytes = file.getBytes(); // 获取文件字节

            // 非种子文件需要先转换为种子
            if (!isTorrentFile) {
                // 获取tracker地址
                String passkey = userService.getPasskey(userService.getUserId());
                String announceUrl = trackerURLService.getAnnounce(passkey);

                // 生成种子文件
                fileBytes = torrentService.createTorrentFromFile(
                        fileBytes,
                        originalFilename, // 使用原始文件名生成种子
                        announceUrl
                );

                filename = originalFilename + ".torrent"; // 强制添加.torrent后缀
            }

            // 验证文件路径安全（处理编码前的原始文件名，避免绕过校验）
            if (originalFilename.contains("..")) { // 检查原始文件名，而非编码后的名称
                throw new RocketPTException("文件路径包含非法字符");
            }

            // 调用原有上传逻辑
            torrentService.upload(id, fileBytes, filename);

            // ------------------- 关键修改：对响应头中的文件名进行编码 -------------------
            // 1. 对文件名进行 UTF-8 URL 编码
            String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8)
                    .replaceAll("\\+", "%20"); // 替换 + 为 %20，符合 URL 编码规范

            // 2. 使用 RFC 5987 标准的 filename* 语法设置响应头
            String contentDisposition = "attachment; filename*=UTF-8''" + encodedFilename;

            return Result.ok();

        } catch (IOException | RocketPTException e) {
            return Result.error("上传失败，站内种子已存在");
        }
    }
    @Operation(summary = "修改种子")
    @PostMapping("/update")
    public Result update(@RequestBody TorrentEntity entity) {
        torrentService.update(entity);
        return Result.ok();
    }


    
    @Operation(summary = "删除种子")
    @PostMapping("/delete")
    public Result delete(@RequestBody Integer[] ids) {
        torrentService.remove(ids);

        return Result.ok();
    }

    @Operation(summary = "获取tracker服务器")
    @PostMapping("/tracker")
    public Result tracker() {
        String announce = trackerURLService.getAnnounce(userService.getPasskey(userService.getUserId()));
        return Result.ok(announce);
    }


    @SaIgnore
    @SneakyThrows
    @Operation(summary = "下载种子")
    @Parameter(name = "id", description = "种子ID", required = true, in = ParameterIn.QUERY)
    @Parameter(name = "passkey", description = "passkey", in = ParameterIn.QUERY)
    @GetMapping("/download")
    public void download(@RequestParam("id") @Positive Integer id,
                         @RequestParam(value = "passkey", required = false) @Positive String passkey,
                         HttpServletResponse response) {

        TorrentEntity entity = torrentService.getById(id);
        if (entity == null) {
            throw new RocketPTException(CommonResultStatus.PARAM_ERROR, I18nMessage.getMessage(
                    "torrent_not_exists"));
        }
        byte[] torrentBytes = torrentService.fetch(id, passkey);
        String filename = entity.getFilename();
        if (StringUtils.isBlank(filename)) {
            filename = entity.getId() + ".torrent";
        }
        if (!StringUtils.endsWithIgnoreCase(filename, ".torrent")) {
            filename = filename + ".torrent";
        }

        filename = URLEncoder.encode(filename, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setContentLength(torrentBytes.length);
        response.setContentType("application/x-bittorrent");
        response.setHeader("Content-Disposition", "attachment;filename=" + filename);
        if (response.isCommitted()) {
            return;
        }
        response.getOutputStream().write(torrentBytes);
        response.getOutputStream().flush();
        // 成功下载后更新 leechers 字段
        torrentService.incrementLeechers(id);
    }

    @Operation(summary = "高级种子列表查询", description = "支持分页、多字段排序和复合条件筛选")
    @ApiResponse(responseCode = "0", description = "操作成功",
            content = {@Content(mediaType = "application/json",
                    schema = @Schema(implementation = TorrentVO.class))
            })
    @PostMapping("/torrentList")
    public Result advancedList(@RequestBody AdvancedTorrentParam param) {
        // 校验排序字段合法性
        param.validOrder(param.getOrderKey(TorrentEntity.class));
        // 构建模糊查询条件
        param.buildLike();
        // 开启分页
        PageUtil.startPage(param);

        // 查询数据（实际业务逻辑需在Service中实现）
        List<TorrentEntity> list = torrentService.advancedSearch(param);

        // 返回分页结果
        return Result.ok(list, PageUtil.getPage(list));
    }

    /**
     * The purpose of the method:
     * 种子的评论
     * {@code @author} Jia
     */

    @PostMapping("/addComment")
    public Result comment(@RequestBody @Valid CommentForm form,
                          HttpServletRequest request) {
        // 获取当前登录用户ID
        Integer userId = userService.getUserId();

        // 构建评论实体
        TorrentCommentEntity comment = new TorrentCommentEntity();
        comment.setTorrentId(form.getTorrentId());
        comment.setUserId(userId);
        comment.setPid(form.getPid());
        comment.setComment(form.getComment());
        comment.setCreateTime(LocalDateTime.now());

        // 保存评论
        torrentCommentService.saveComment(comment);

        return Result.ok();
    }

    @GetMapping("/comments") // 使用GET方法更符合语义
    public Result getComments(
            @RequestParam("torrentId") Integer torrentId,
            @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
            @RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize
    ) {
        // 分页查询种子评论（按时间倒序）
        PageInfo<TorrentCommentVO> pageInfo = torrentCommentService.getCommentsByTorrentId(
                torrentId, pageNum, pageSize
        );

        return Result.ok(pageInfo);
    }

    @GetMapping("/GetUserInfo")
    public Result GetUserInfo() {
        UserEntity user = userService.getUserById(userService.getUserId());
        Map<String,String> res = new HashMap<>();
        Long number = torrentService.count();
        res.put("download",user.getDownload().toString());
        res.put("upload",user.getUpload().toString());
        res.put("number",number.toString());
        return Result.ok(res);
    }




}
